﻿package com.bizmlib.lang
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.utils.setTimeout;
	
	
	public class Locale extends EventDispatcher
	{
		private static var stringsContainer:Object;
		private static var urlLoaders:Array;
		private static var defaultLang:String;
		private static var loadedLangCodes:Array;
		
		private static var singleInstance:Locale;
		
		
		public static function setString(stringID:String, languageCode:String, stringValue:String, noEvents:Boolean = false):void
		{
			//trace(getInstance() + ".setString(" + arguments + ")");
			
			checkStringsContainer();
			
			if(!stringsContainer[stringID])
			{
				stringsContainer[stringID] = new Object();
				//trace("create new contaner for '" + stringID + "'");
			}
			
			stringsContainer[stringID][languageCode] = stringValue;
			
			if(!noEvents)
			{
				getInstance().dispatchEvent(new LocaleEvent(LocaleEvent.CHANGE));
			}
		}
		public static function loadString(id:String):String
		{
			checkStringsContainer();
			
			return stringsContainer[id] ? stringsContainer[id][getDefaultLang()] : "";
		}
		public static function loadStringEx(id:String, langCode:String):String
		{
			checkStringsContainer();
			
			return stringsContainer[id] ? stringsContainer[id][langCode] : "";
		}
		public static function parseXML(xml:XML):void
		{
			var langCode:String = xml.file.attribute("source-language");
			var list:XMLList = xml.file.body.*;
			for each(var node:XML in list)
			{
				if(node.localName()=="trans-unit")
				{
					var str:String = node.source[0].toString();
					setString(String(node.@resname), langCode, str, true);
				}
			}
			
			addLoadedLangCode(langCode);
		}
		public static function loadXML(url:String):EventDispatcher
		{
			var r:URLRequest = new URLRequest(url);
			var urlLoader:URLLoader = new URLLoader();
			urlLoader.addEventListener(Event.COMPLETE, urlLoaderComplete);
			urlLoader.addEventListener(IOErrorEvent.IO_ERROR, urlLoaderIOError);
			urlLoader.addEventListener(ProgressEvent.PROGRESS, urlLoaderProgress);
			urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, urlLoaderSecurityError);
			
			checkURLLoadersArray();
			var urlLoadersEntry:Object = {urlLoader:urlLoader, eventDispatcher:new EventDispatcher()};
			urlLoaders.push(urlLoadersEntry);
			
			//setTimeout(urlLoader.load, 5, r);
			setTimeout(startXMLLoad, 5, urlLoader, r);
			//urlLoader.load(r);
			
			return urlLoadersEntry.eventDispatcher;
		}
		public static function getInstance():Locale
		{
			checkSingleInstance();
			return singleInstance;
		}
		
		public static function setDefaultLang(langCode:String):void
		{
			if(langCode==defaultLang)
			{
				return;
			}
			defaultLang = langCode;
			getInstance().dispatchEvent(new LocaleEvent(LocaleEvent.CHANGE));
		}
		public static function getDefaultLang():String
		{
			return defaultLang;
		}
		public static function getAllLangCodes():Array
		{
			checkLoadedLangCodesArray();
			return loadedLangCodes.concat();
		}
		
		
		private static function checkStringsContainer():void
		{
			if(!stringsContainer)
			{
				stringsContainer = new Object();
			}
		}
		private static function checkSingleInstance():void
		{
			if(!singleInstance)
			{
				singleInstance = new Locale();
			}
		}
		private static function checkURLLoadersArray():void
		{
			if(!urlLoaders)
			{
				urlLoaders = new Array();
			}
		}
		private static function addLoadedLangCode(langCode:String):void
		{
			checkLoadedLangCodesArray();
			
			for each(var currentLangCode:String in loadedLangCodes)
			{
				if(currentLangCode==langCode)
				{
					return;
				}
			}
			
			loadedLangCodes.push(langCode);
		}
		private static function checkLoadedLangCodesArray():void
		{
			if(!loadedLangCodes)
			{
				loadedLangCodes = new Array();
			}
		}
		
		
		private static function findURLLoadersEntry(urlLoader:URLLoader, removeFromArray:Boolean = false):Object
		{
			for(var i:Number=0; i<urlLoaders.length; i++)
			{
				var entry:Object = urlLoaders[i];
				if(entry.urlLoader==urlLoader)
				{
					if(removeFromArray)
					{
						urlLoaders.splice(i, 1);
					}
					return entry;
				}
			}
			
			return null;
		}
		
		private static function startXMLLoad(urlLoader:URLLoader, urlRequest:URLRequest):void
		{
			urlLoader.load(urlRequest);
		}
		private static function urlLoaderProgress(event:ProgressEvent):void
		{
			var urlLoadersEntry:Object = findURLLoadersEntry(event.target as URLLoader, false);
			
			urlLoadersEntry.eventDispatcher.dispatchEvent(new LocaleEvent(LocaleEvent.LOAD_PROGRESS, {bytesLoaded:event.bytesLoaded, bytesTotal:event.bytesTotal}));
		}
		private static function urlLoaderComplete(event:Event):void
		{
			var urlLoader:URLLoader = event.target as URLLoader;
			var urlLoadersEntry:Object = findURLLoadersEntry(urlLoader, true);
			
			parseXML(XML(urlLoader.data));
			
			getInstance().dispatchEvent(new LocaleEvent(LocaleEvent.CHANGE));
			
			clearURLLoader(urlLoadersEntry.urlLoader);
			
			urlLoadersEntry.eventDispatcher.dispatchEvent(new LocaleEvent(LocaleEvent.LOAD_DONE, true));
			urlLoadersEntry.eventDispatcher = null;
			urlLoadersEntry.urlLoader = null;
		}
		private static function urlLoaderIOError(event:IOErrorEvent):void
		{
			var urlLoadersEntry:Object = findURLLoadersEntry(event.target as URLLoader, true);
			
			clearURLLoader(urlLoadersEntry.urlLoader);
			
			urlLoadersEntry.eventDispatcher.dispatchEvent(new LocaleEvent(LocaleEvent.LOAD_DONE, false, event.text));
			urlLoadersEntry.eventDispatcher = null;
			urlLoadersEntry.urlLoader = null;
		}
		private static function urlLoaderSecurityError(event:SecurityErrorEvent):void
		{
			var urlLoadersEntry:Object = findURLLoadersEntry(event.target as URLLoader, true);
			
			clearURLLoader(urlLoadersEntry.urlLoader);
			
			urlLoadersEntry.eventDispatcher.dispatchEvent(new LocaleEvent(LocaleEvent.LOAD_DONE, false, event.text));
			urlLoadersEntry.eventDispatcher = null;
			urlLoadersEntry.urlLoader = null;
		}
		private static function clearURLLoader(urlLoader:URLLoader):void
		{
			urlLoader.removeEventListener(Event.COMPLETE, urlLoaderComplete);
			urlLoader.removeEventListener(IOErrorEvent.IO_ERROR, urlLoaderIOError);
			urlLoader.removeEventListener(ProgressEvent.PROGRESS, urlLoaderProgress);
			urlLoader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, urlLoaderSecurityError);
		}
		
		
		override public function toString():String
		{
			return "[Locale" + (defaultLang ? ("\tdefaultLang=\"" + defaultLang + "\"") : "") + "]";
		}
	}
}